import bcrypt from 'bcryptjs'
import jwt from 'jsonwebtoken'
import { prisma } from '@/lib/database'
import { config } from '@/config/env'
import { AuthenticationError, ValidationError, ConflictError } from '@/middleware/errorHandler'

// 类型定义
export interface RegisterData {
  username: string
  email: string
  password: string
  displayName?: string
}

export interface LoginData {
  email: string
  password: string
}

export interface JWTPayload {
  sub: string
  email: string
  username: string
  role: 'developer' | 'admin'
  iat: number
  exp: number
  iss: string
  aud: string
}

export interface AuthTokens {
  accessToken: string
  refreshToken: string
  expiresIn: number
}

export interface UserProfile {
  id: string
  username: string
  email: string
  displayName?: string
  avatarUrl?: string
  bio?: string
  websiteUrl?: string
  githubUrl?: string
  verified: boolean
  emailVerified: boolean
  createdAt: Date
  updatedAt: Date
}

export class AuthService {
  // 密码哈希
  async hashPassword(password: string): Promise<string> {
    return await bcrypt.hash(password, config.security.bcryptRounds)
  }

  // 密码验证
  async verifyPassword(password: string, hash: string): Promise<boolean> {
    return await bcrypt.compare(password, hash)
  }

  // 生成JWT Token
  generateTokens(user: { id: string; email: string; username: string; role?: string }): AuthTokens {
    const payload: Omit<JWTPayload, 'iat' | 'exp'> = {
      sub: user.id,
      email: user.email,
      username: user.username,
      role: (user.role || 'developer') as 'developer' | 'admin',
      iss: config.jwt.issuer,
      aud: config.jwt.audience
    }

    const accessToken = jwt.sign(payload, config.jwt.secret, {
      expiresIn: config.jwt.expiresIn
    } as any)

    const refreshToken = jwt.sign(payload, config.jwt.secret, {
      expiresIn: config.jwt.refreshExpiresIn
    } as any)

    // 解析过期时间（秒）
    const expiresIn = this.parseExpirationTime(config.jwt.expiresIn)

    return {
      accessToken,
      refreshToken,
      expiresIn
    }
  }

  // 验证JWT Token
  verifyToken(token: string): JWTPayload {
    try {
      return jwt.verify(token, config.jwt.secret, {
        issuer: config.jwt.issuer,
        audience: config.jwt.audience
      }) as JWTPayload
    } catch (error) {
      if (error instanceof jwt.TokenExpiredError) {
        throw new AuthenticationError('Token expired')
      } else if (error instanceof jwt.JsonWebTokenError) {
        throw new AuthenticationError('Invalid token')
      }
      throw new AuthenticationError('Token verification failed')
    }
  }

  // 用户注册
  async register(data: RegisterData): Promise<{ user: UserProfile; tokens: AuthTokens }> {
    // 验证输入数据
    if (!data.username || data.username.length < 3) {
      throw new ValidationError('Username must be at least 3 characters long')
    }

    if (!data.email || !this.isValidEmail(data.email)) {
      throw new ValidationError('Invalid email address')
    }

    if (!data.password || data.password.length < 8) {
      throw new ValidationError('Password must be at least 8 characters long')
    }

    // 检查用户名和邮箱是否已存在
    const existingUser = await prisma.developer.findFirst({
      where: {
        OR: [
          { username: data.username },
          { email: data.email }
        ]
      }
    })

    if (existingUser) {
      if (existingUser.username === data.username) {
        throw new ConflictError('Username already exists')
      }
      if (existingUser.email === data.email) {
        throw new ConflictError('Email already exists')
      }
    }

    // 创建新用户
    const passwordHash = await this.hashPassword(data.password)
    const user = await prisma.developer.create({
      data: {
        username: data.username,
        email: data.email,
        passwordHash,
        displayName: data.displayName || data.username,
        status: 'active',
        verified: false,
        emailVerified: false
      }
    })

    // 生成Token
    const tokens = this.generateTokens(user)

    // 返回用户信息（不包含密码）
    const userProfile = this.formatUserProfile(user)

    return { user: userProfile, tokens }
  }

  // 用户登录
  async login(data: LoginData): Promise<{ user: UserProfile; tokens: AuthTokens }> {
    // 查找用户
    const user = await prisma.developer.findUnique({
      where: { email: data.email }
    })

    if (!user) {
      throw new AuthenticationError('Invalid email or password')
    }

    // 检查用户状态
    if (user.status !== 'active') {
      throw new AuthenticationError('Account is suspended')
    }

    // 验证密码
    const isValidPassword = await this.verifyPassword(data.password, user.passwordHash)
    if (!isValidPassword) {
      throw new AuthenticationError('Invalid email or password')
    }

    // 更新最后登录时间
    await prisma.developer.update({
      where: { id: user.id },
      data: { lastLoginAt: new Date() }
    })

    // 生成Token
    const tokens = this.generateTokens(user)

    // 返回用户信息
    const userProfile = this.formatUserProfile(user)

    return { user: userProfile, tokens }
  }

  // 刷新Token
  async refreshToken(refreshToken: string): Promise<AuthTokens> {
    try {
      const payload = this.verifyToken(refreshToken)
      
      // 验证用户是否仍然存在且活跃
      const user = await prisma.developer.findUnique({
        where: { id: payload.sub }
      })

      if (!user || user.status !== 'active') {
        throw new AuthenticationError('User not found or inactive')
      }

      // 生成新的Token
      return this.generateTokens(user)
    } catch (error) {
      throw new AuthenticationError('Invalid refresh token')
    }
  }

  // 获取用户资料
  async getProfile(userId: string): Promise<UserProfile> {
    const user = await prisma.developer.findUnique({
      where: { id: userId }
    })

    if (!user) {
      throw new AuthenticationError('User not found')
    }

    return this.formatUserProfile(user)
  }

  // 更新用户资料
  async updateProfile(userId: string, data: Partial<UserProfile>): Promise<UserProfile> {
    // 过滤允许更新的字段
    const allowedFields = ['displayName', 'bio', 'websiteUrl', 'githubUrl', 'avatarUrl']
    const updateData: any = {}

    for (const field of allowedFields) {
      if (data[field as keyof UserProfile] !== undefined) {
        updateData[field] = data[field as keyof UserProfile]
      }
    }

    const user = await prisma.developer.update({
      where: { id: userId },
      data: updateData
    })

    return this.formatUserProfile(user)
  }

  // 辅助方法：格式化用户资料
  private formatUserProfile(user: any): UserProfile {
    return {
      id: user.id,
      username: user.username,
      email: user.email,
      displayName: user.displayName,
      avatarUrl: user.avatarUrl,
      bio: user.bio,
      websiteUrl: user.websiteUrl,
      githubUrl: user.githubUrl,
      verified: user.verified,
      emailVerified: user.emailVerified,
      createdAt: user.createdAt,
      updatedAt: user.updatedAt
    }
  }

  // 辅助方法：验证邮箱格式
  private isValidEmail(email: string): boolean {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
    return emailRegex.test(email)
  }

  // 辅助方法：解析过期时间
  private parseExpirationTime(expiration: string): number {
    const match = expiration.match(/^(\d+)([smhd])$/)
    if (!match) return 900 // 默认15分钟

    const value = parseInt(match[1])
    const unit = match[2]

    switch (unit) {
      case 's': return value
      case 'm': return value * 60
      case 'h': return value * 60 * 60
      case 'd': return value * 60 * 60 * 24
      default: return 900
    }
  }
}
